package edu.gatech.spacetraderteam3.model;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import edu.gatech.spacetraderteam3.debug.Debug;

/**
 * Player class (now with skills!)
 * 
 * @author Aaron
 * @version 3.5
 */
public class Player extends Actor implements Serializable {

    /**
     * The serial Version UID for this Player
     */
    private static final long serialVersionUID = 3951209105141157459L;

    /**
     * The starting set of skill points
     */
    public static final int INITIAL_SKILL_POINTS = 16;

    /**
     * An array of 4 the skills
     */
    public static final String[] SKILLS = new String[] { "Pilot", "Fighter", "Trader",
            "Engineer" };

    /**
     * The amount fuel a purchase of fuel will provide
     */
    private static final int FUEL_INCREMENT = 100;

    /**
     * The cost of fuel
     */
    private static final int FUEL_COST = 50;

    /**
     * The index in SKILLS[] for Pilot
     */
    private static final int PILOT = 0;

    /**
     * The index in SKILLS[] for Fighter
     */
    private static final int FIGHT = 1;

    /**
     * The index in SKILLS[] for Trader
     */
    private static final int TRADE = 2;

    /**
     * The index in SKILLS[] for Engineer
     */
    private static final int ENG = 3;

    /**
     * The amount of initial credits
     */
    private static final int STARTING_CREDITS = 1000;

    /**
     * The number of skill points allocated for each field shown
     */
    private int piloting, fighting, trading, engineering, credits; // , fuel; unused? //
                                                                   // skills include

    /**
     * The current planet
     */
    private SpacePlanet planet;

    /**
     * Constructor for the Player. Sets the name and skills.
     * 
     * @param name
     *            The name of the player
     * @param skills
     *            the skills the player has chosen
     */
    public Player(String name, int[] skills) {
        super(name, Faction.PLAYER, new Gnat());
        setAll(skills);
        credits = STARTING_CREDITS;
        // fuel = this.ship.getMaxFuel(); //unused?

        Debug.write("Player created with the following:", 1);
        Debug.write("Name: " + name, 1);
        Debug.write("Pilot: " + skills[PILOT], 1);
        Debug.write("Fighter: " + skills[FIGHT], 1);
        Debug.write("Trader: " + skills[TRADE], 1);
        Debug.write("Engineering: " + skills[ENG], 1);
    }

    /**
     * Default constructor for the Player class. Default name is Derpderp and skills are all 0
     */
    public Player() {
        this("Derpderp", new int[] { PILOT, FIGHT, TRADE, ENG });
    }

    /**
     * Sets the piloting skill.
     * 
     * @param piloting
     *            The Piloting skill value
     */
    public void setPiloting(int piloting) {
        this.piloting = piloting;
    }

    /**
     * Gets Piloting skill value
     * 
     * @return Piloting skill value
     */
    public int getPiloting() {
        return this.piloting;
    }

    /**
     * Sets the fighting skill value
     * 
     * @param fighting
     *            The Fighting skill value
     */
    public void setFighting(int fighting) {
        this.fighting = fighting;
    }

    /**
     * Setter for planet.
     * 
     * @param sp
     *            Planet user is now on
     */
    public void setPlanet(SpacePlanet sp) {
        this.planet = sp;
    }

    /**
     * Getter for planet.
     * 
     * @return Planet the user is on currently
     */
    public SpacePlanet getPlanet() {
        return this.planet;
    }

    /**
     * Returns the player's fighting skill value
     * 
     * @return The fighting skill value
     */
    public int getFighting() {
        return this.fighting;
    }

    /**
     * Sets the player's trading value
     * 
     * @param trading
     *            The trading skill value
     */
    public void setTrading(int trading) {
        this.trading = trading;
    }

    /**
     * Says whether the Player can fly to a given System.
     * 
     * @param system
     *            System you're trying to fly to
     * @return True if you can fly there, false otherwise
     */
    public boolean canFlyTo(SpaceSolarSystem system) {
        final SpaceSolarSystem mine = planet.getSystem();
        return this.ship.getCurrentFuel() > mine.distanceTo(system);
    }

    /**
     * Returns the player's trading skill value
     * 
     * @return The trading skill value
     */
    public int getTrading() {
        return this.trading;
    }

    /**
     * Sets the engineering skill value
     * 
     * @param engineering
     *            The engineering value
     */
    public void setEngineering(int engineering) {
        this.engineering = engineering;
    }

    /**
     * Returns the player's engineering skill value
     * 
     * @return The engineering skill value
     */
    public int getEngineering() {
        return this.engineering;
    }

    /**
     * Returns how many credits the player has
     * 
     * @return Number of credits
     */
    public int getCredits() {
        return credits;
    }

    /**
     * Adds credits to the Player's total
     * 
     * @param credits
     *            Number of credits to add
     */
    public void addCredits(int credits) {
        this.credits += credits;
    }

    /**
     * Removes credits from the Player's total
     * 
     * @param credits
     *            Number of credits to remove
     */
    public void removeCredits(int credits) {
        this.credits -= credits;
    }

    /**
     * Takes all the players skills in an array and sets them
     * 
     * @param all
     *            All of the player's skills
     */
    public final void setAll(int[] all) {
        setPiloting(all[PILOT]);
        setFighting(all[FIGHT]);
        setTrading(all[TRADE]);
        setEngineering(all[ENG]);
    }

    /**
     * Getter for max weight.
     * 
     * @return The ship's max weight.
     */
    public int getMaxWeight() {
        return ship.getMaxWeight();
    }

    /**
     * Getter for current weight.
     * 
     * @return The ship's current weight.
     */
    public int getCurrentWeight() {
        return ship.getCurrentWeight();
    }

    /**
     * Whether or not the user can buy something.
     * 
     * @param cost
     *            Cost of thing in question
     * @return True if user can buy, false otherwise
     */
    public boolean canBuy(int cost) {
        return cost < credits;
    }

    /**
     * Uses up fuel.
     * 
     * @param s
     *            SolarSystem you're traveling to.
     */
    public void useFuel(SpaceSolarSystem s) {
        ship.useFuel((int) s.distanceTo(this.planet.getSystem()));
    }

    /**
     * Getter for inventory.
     * 
     * @return HashMap of Resource -> Integers (User inventory.)
     */
    public Map<Resource, Integer> getItems() {
        final HashMap<Resource, Integer> inv = new HashMap<Resource, Integer>();
        for (Resource r : Resource.values()) {
            inv.put(r, inventory.getResource(r));
        }
        return inv;
    }

    /**
     * Returns a string of all the Player's skills
     * 
     * @return The string composed of all of the player's skills
     */
    public String toString() {
        final String skills = "Piloting = " + piloting + ", Fighting = " + fighting
                + ", Trading = " + trading + ", Engineering =  " + engineering;
        return super.toString() + ", " + skills;
    }

    /**
     * Called when pirates loot you. Removes half your credits and half of a random
     * resource in your inventory.
     */
    public void becomeLooted() {
        this.credits = credits >> 1;
        this.inventory.becomeLooted();
        this.ship.calculateWeight(inventory);
    }

    /**
     * Getter for ship's fuel.
     * 
     * @return The ship's fuel.
     */
    public int getFuel() {
        return ship.getCurrentFuel();
    }

    /**
     * Called when refueling the player's ship.
     */
    public void reFuel() {
        if (ship.getCurrentFuel() + FUEL_INCREMENT < ship.getMaxFuel()) {
            if (credits >= FUEL_COST) {
                credits -= FUEL_COST;
                if (ship.addFuel(FUEL_INCREMENT)) {
                    Debug.write("Added " + FUEL_INCREMENT + "fuel", Debug.VERBOSE);
                }
            }
        } else {
            final int price = calcFuelCost();
            if (credits >= price) {
                if (ship.addFuel(ship.getMaxFuel() - ship.getCurrentFuel())) {
                    credits -= price;
                }
            }
        }

    }

    /**
     * Calculates the fuel cost, if player has < FUEL_INCREMENT fuel missing.
     * 
     * @return The cost to fill up the rest of the tank.
     */
    public int calcFuelCost() {
        return (ship.getMaxFuel() - ship.getCurrentFuel()) > FUEL_INCREMENT ? FUEL_COST
                : ((ship.getMaxFuel() - ship.getCurrentFuel()) * FUEL_COST / FUEL_INCREMENT);
    }
}
